#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    agAddrFormat = new QActionGroup(this);
    agFirstFormat = new QActionGroup(this);
    agSecFormat = new QActionGroup(this);
    agFirstEndian = new QActionGroup(this);
    agSecEndian = new QActionGroup(this);

    this->enAddrFormat = FORMAT_HEX;
    this->enFirstFormat = FORMAT_HEX;
    this->enSecFormat = FORMAT_CHAR;
    this->enFirstEndian = LITTLE_ENDIAN;
    this->enSecEndian = LITTLE_ENDIAN;

    defalutPath = "";

    agAddrFormat->addAction(ui->actionAddrHex);
    agAddrFormat->addAction(ui->actionAddrInt);
    agAddrFormat->addAction(ui->actionAddrOct);

    agFirstFormat->addAction(ui->actionFirstBin);
    agFirstFormat->addAction(ui->actionFirstChar);
    agFirstFormat->addAction(ui->actionFirstOct);
    agFirstFormat->addAction(ui->actionFirstInt);
    agFirstFormat->addAction(ui->actionFirstHex);

    agSecFormat->addAction(ui->actionSecBin);
    agSecFormat->addAction(ui->actionSecChar);
    agSecFormat->addAction(ui->actionSecOct);
    agSecFormat->addAction(ui->actionSecInt);
    agSecFormat->addAction(ui->actionSecHex);

    agFirstEndian->addAction(ui->actionFirstBigEndian);
    agFirstEndian->addAction(ui->actionFirstLittleEndian);

    agSecEndian->addAction(ui->actionSecBigEndian);
    agSecEndian->addAction(ui->actionSecLittleEndian);

    connect(agAddrFormat, SIGNAL(triggered(QAction*)), this, SLOT(onAGAddrFormatTriggered()));
    connect(agFirstFormat, SIGNAL(triggered(QAction*)), this, SLOT(onAGFirstFormatTriggered()));
    connect(agFirstEndian, SIGNAL(triggered(QAction*)), this, SLOT(onAGFirstEndianTriggered()));
    connect(agSecFormat, SIGNAL(triggered(QAction*)), this, SLOT(onAGSecFormatTriggered()));
    connect(agSecEndian, SIGNAL(triggered(QAction*)), this, SLOT(onAGSecEndianTriggered()));


    this->bntOpen = new QAction(QIcon(":/static/imgs/open-1.png"), "", this);
    this->bntOpen->setToolTip(tr("Open"));
    connect(this->bntOpen, SIGNAL(triggered()), this,   SLOT(on_actionOpen_triggered()));

    this->bntClose = new QAction(QIcon(":/static/imgs/close.png"), "", this);
    this->bntClose->setToolTip(tr("Close"));
    connect(this->bntClose, SIGNAL(triggered()), this,   SLOT(on_actionClose_triggered()));

    this->bntCloseAll = new QAction(QIcon(":/static/imgs/close.png"), "", this);
    this->bntCloseAll->setToolTip(tr("Close All"));
    connect(this->bntCloseAll, SIGNAL(triggered()), this, SLOT(on_actionClose_All_triggered()));

    this->bntSearch = new QAction(QIcon(":/static/imgs/search.png"), "", this);
    this->bntSearch->setToolTip(tr("Search"));
    connect(this->bntSearch, SIGNAL(triggered()), this, SLOT(on_actionFind_triggered()));

    this->bntBookmark = new QAction(QIcon(":/static/imgs/bookmark.png"), "", this);
    this->bntBookmark->setToolTip(tr("Bookmark"));
    connect(this->bntBookmark, SIGNAL(triggered()), this, SLOT(on_actionBookmark_triggered()));

    this->bntBookAdd = new QAction(QIcon(":/static/imgs/bookmark-add.png"), "", this);
    this->bntBookAdd->setToolTip(tr("Add Bookmark"));
    connect(this->bntBookAdd, SIGNAL(triggered()), this, SLOT(on_actionAdd_Bookmark_triggered()));
\
    QMenu *menuAddrFormat = new QMenu(this);
    menuAddrFormat->addAction(ui->actionAddrHex);
    menuAddrFormat->addAction(ui->actionAddrInt);
    menuAddrFormat->addAction(ui->actionAddrOct);

    QMenu *menuFirstFormat = new QMenu(this);
    menuFirstFormat->addAction(ui->actionFirstHex);
    menuFirstFormat->addAction(ui->actionFirstInt);
    menuFirstFormat->addAction(ui->actionFirstOct);
    menuFirstFormat->addAction(ui->actionFirstBin);
    menuFirstFormat->addAction(ui->actionFirstChar);
    menuFirstFormat->addSeparator();
    menuFirstFormat->addAction(ui->actionFirstBigEndian);
    menuFirstFormat->addAction(ui->actionFirstLittleEndian);

    QMenu *menuSectFormat = new QMenu(this);
    menuSectFormat->addAction(ui->actionSecHex);
    menuSectFormat->addAction(ui->actionSecInt);
    menuSectFormat->addAction(ui->actionSecOct);
    menuSectFormat->addAction(ui->actionSecChar);
    menuSectFormat->addAction(ui->actionSecBin);
    menuSectFormat->addSeparator();
    menuSectFormat->addAction(ui->actionSecBigEndian);
    menuSectFormat->addAction(ui->actionSecLittleEndian);

    this->bntAddrFormat = new QToolButton(this);
    this->bntAddrFormat->setIcon(QIcon(":/static/imgs/addr.png"));
    this->bntAddrFormat->setToolTip(tr("Addr. Format"));
    this->bntAddrFormat->setMenu(menuAddrFormat);
    this->bntAddrFormat->setPopupMode(QToolButton::InstantPopup);

    this->bntFirstFormat = new QToolButton(this);
    this->bntFirstFormat->setIcon(QIcon(":/static/imgs/left.png"));
    this->bntFirstFormat->setToolTip(tr("Left Format"));
    this->bntFirstFormat->setMenu(menuFirstFormat);
    this->bntFirstFormat->setPopupMode(QToolButton::InstantPopup);

    this->bntSecFormat = new QToolButton(this);
    this->bntSecFormat->setIcon(QIcon(":/static/imgs/right.png"));
    this->bntSecFormat->setToolTip(tr("Right Format"));
    this->bntSecFormat->setMenu(menuSectFormat);
    this->bntSecFormat->setPopupMode(QToolButton::InstantPopup);

    ui->toolBar->addAction(this->bntOpen);
    ui->toolBar->addAction(this->bntClose);
    ui->toolBar->addAction(this->bntCloseAll);
    ui->toolBar->addSeparator();
    ui->toolBar->addAction(this->bntSearch);
    ui->toolBar->addAction(this->bntBookAdd);
    ui->toolBar->addAction(this->bntBookmark);
    ui->toolBar->addSeparator();
    ui->toolBar->addWidget(this->bntAddrFormat);
    ui->toolBar->addWidget(this->bntFirstFormat);
    ui->toolBar->addWidget(this->bntSecFormat);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actionExit_triggered()
{
    exit(0);
}

void MainWindow::on_actionOpen_triggered()
{
    QString filename = QFileDialog::getOpenFileName(this, "Open File", defalutPath, "*");

    qDebug() << filename;

    if (!QFile::exists(filename))
    {
        QMessageBox::information(this, tr("Information"),
                                 tr("File Not Exist!\n") + "File Name: " + filename,
                                       QMessageBox::Ok,
                                       QMessageBox::Ok);

        return;
    }

    if (swMap.contains(filename))
    {
        onActionFilesTriggered(filename);
        return;
    }

    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly))
    {
        QMessageBox::information(this, tr("Information"),
                                 tr("Cannot open file!\n") + "File Name" + filename,
                                       QMessageBox::Ok,
                                       QMessageBox::Ok);

        return;
    }


    QByteArray bytes = file.readAll();
    file.close();


    // 窗体
    MdiSubWindow *sw = new MdiSubWindow(this);
    BinView *view = new BinView(bytes, this);
    view->setAddrFormat(enAddrFormat);
    view->setFirstFormat(enFirstFormat);
    view->setSecFormat(enSecFormat);
    view->setFirstEndian(enFirstEndian);
    view->setSecEndian(enSecEndian);
    view->setAttribute(Qt::WA_DeleteOnClose);

    view->setWindowTitle(filename);

    sw->setWidget(view);
    sw->setWindowIcon(QIcon(":/static/imgs/wicon.jpg"));
    sw->setAttribute(Qt::WA_DeleteOnClose);

    ui->mdiArea->addSubWindow(sw);

    view->show();

    bvMap.insert(filename, view);
    swMap.insert(filename, sw);


    // 窗口列表菜单
    Action *action = new Action(filename);
    action->setText(filename);
    ui->menuFiles->addAction(action);
    actionMap.insert(filename, action);
    connect(action, SIGNAL(triggered(QString)), this, SLOT(onActionFilesTriggered(QString)));
    connect(sw, SIGNAL(onClose(QString)), this, SLOT(actionCloseByPath(QString)));

    ui->mdiArea->showMaximized();
}

void MainWindow::actionCloseByPath(QString path)
{
    bvMap.remove(path);
    swMap.remove(path);

    Action *action = actionMap.value(path);
    if (action)
    {
        actionMap.remove(path);
        ui->menuFiles->removeAction(action);
        action->setVisible(false);

        delete action;
    }
}

void MainWindow::on_actionClose_triggered()
{
    MdiSubWindow *sw = (MdiSubWindow *)ui->mdiArea->currentSubWindow();
    if (!sw)
    {
        return;
    }

    qDebug() << "close!";
    sw->close();
}

void MainWindow::onActionFilesTriggered(QString name)
{
    MdiSubWindow *view = swMap.value(name);
    if (view)
    {
        ui->mdiArea->setActiveSubWindow(view);
    }
}

void MainWindow::on_actionRecent_hovered()
{

}

void MainWindow::on_actionBookmark_triggered()
{
    MdiSubWindow *sw = (MdiSubWindow *)ui->mdiArea->currentSubWindow();
    if (!sw)
    {
        return;
    }

    QString title= sw->windowTitle();

    BinView *bv = bvMap.value(title);
    if (bv)
    {
        bv->showBookmark();
    }

    qDebug() << "212121";
}

void MainWindow::on_actionAdd_Bookmark_triggered()
{
    MdiSubWindow *sw = (MdiSubWindow *)ui->mdiArea->currentSubWindow();
    if (!sw)
    {
        QMessageBox::information(this, tr("Notice"), "No active window.");
        return;
    }

    QString title= sw->windowTitle();

    BinView *bv = bvMap.value(title);
    if (!bv)
    {
        QMessageBox::information(this, tr("Notice"), "No active view.");
        return;
    }

    if (!bv->hasValidIndex())
    {
        QMessageBox::information(this, tr("Notice"), "No selected byte.");
        return;
    }

    DialogAddBookmark add;
    int accepted = add.exec();
    if (accepted == QDialog::Accepted)
    {
        bv->addBookmark(add.title(), add.remark());
    }
}

void MainWindow::on_actionFind_triggered()
{
    MdiSubWindow *sw = (MdiSubWindow *)ui->mdiArea->currentSubWindow();
    if (!sw)
    {
        QMessageBox::information(this, tr("Notice"), tr("No active window."));
        return;
    }

    QString title= sw->windowTitle();

    BinView *bv = bvMap.value(title);
    if (!bv)
    {
        QMessageBox::information(this, tr("Notice"), tr("No active view."));
        return;
    }

    if (!bv->hasValidIndex())
    {
        QMessageBox::information(this, tr("Notice"), tr("No selected byte."));
        return;
    }

    DialogSearch search;
    int accepted = search.exec();
    if (accepted == QDialog::Accepted)
    {
        QByteArray b = search.content();
        if (b.isEmpty())
        {
            QMessageBox::information(this, tr("Notice"), tr("No search content set."));
            return;
        }

        bv->search(b, search.searchType(), (search.pos() != 0));
    }
}

void MainWindow::on_actionGoto_triggered()
{
    MdiSubWindow *sw = (MdiSubWindow *)ui->mdiArea->currentSubWindow();
    if (!sw)
    {
        QMessageBox::information(this, tr("Notice"), tr("No active window."));
        return;
    }

    QString title= sw->windowTitle();

    BinView *bv = bvMap.value(title);
    if (!bv)
    {
        QMessageBox::information(this, tr("Notice"), tr("No active view."));
        return;
    }

    DialogGoto gotoLine;
    int accepted = gotoLine.exec();
    if (accepted == QDialog::Accepted)
    {
        int addr = (int)gotoLine.address();
        bv->gotoLine(addr);
    }
}

void MainWindow::on_actionAbout_triggered()
{
    DialogAbout about;

    about.exec();
}

void MainWindow::on_actionClose_All_triggered()
{
    QMap<QString, MdiSubWindow *>::const_iterator i = swMap.constBegin();
     while (i != swMap.constEnd())
     {

         MdiSubWindow *sw = i.value();
         if (sw)
         {
            sw->close();
         }
         ++i;
     }

     swMap.clear();
}

void MainWindow::on_actionClose_All_2_triggered()
{
    this->on_actionClose_All_triggered();
}

void MainWindow::onAGAddrFormatTriggered()
{
    if (ui->actionAddrInt->isChecked())
    {
        enAddrFormat = FORMAT_DEC;
    }
    else if (ui->actionAddrOct->isChecked())
    {
        enAddrFormat = FORMAT_OCT;
    }
    else
    {
        enAddrFormat = FORMAT_HEX;
    }


    MdiSubWindow * sw = (MdiSubWindow *)ui->mdiArea->currentSubWindow();
    if (!sw)
    {
        return;
    }

    QString path = swMap.key(sw);
    if (path.isEmpty())
    {
        return;
    }

    BinView *bv = bvMap.value(path);
    if (!bv)
    {
        return;
    }

    bv->setAddrFormat(enAddrFormat);
}

void MainWindow::onAGFirstFormatTriggered()
{
    if (ui->actionFirstBin->isChecked())
    {
        enFirstFormat = FORMAT_BIN;
    }
    else if (ui->actionFirstChar->isChecked())
    {
        enFirstFormat = FORMAT_CHAR;
    }
    else if (ui->actionFirstInt->isChecked())
    {
        enFirstFormat = FORMAT_DEC;
    }
    else if (ui->actionFirstOct->isChecked())
    {
        enFirstFormat = FORMAT_OCT;
    }
    else
    {
        enFirstFormat = FORMAT_HEX;
    }

    MdiSubWindow * sw = (MdiSubWindow *)ui->mdiArea->currentSubWindow();
    if (!sw)
    {
        return;
    }

    QString path = swMap.key(sw);
    if (path.isEmpty())
    {
        return;
    }

    BinView *bv = bvMap.value(path);
    if (!bv)
    {
        return;
    }

    bv->setFirstFormat(enFirstFormat);
}

void MainWindow::onAGSecFormatTriggered()
{
    if (ui->actionSecBin->isChecked())
    {
        enSecFormat = FORMAT_BIN;
    }
    else if (ui->actionSecHex->isChecked())
    {
        enSecFormat = FORMAT_HEX;
    }
    else if (ui->actionSecInt->isChecked())
    {
        enSecFormat = FORMAT_DEC;
    }
    else if (ui->actionSecOct->isChecked())
    {
        enSecFormat = FORMAT_OCT;
    }
    else
    {
        enSecFormat = FORMAT_CHAR;
    }

    MdiSubWindow * sw = (MdiSubWindow *)ui->mdiArea->currentSubWindow();
    if (!sw)
    {
        return;
    }

    QString path = swMap.key(sw);
    if (path.isEmpty())
    {
        return;
    }

    BinView *bv = bvMap.value(path);
    if (!bv)
    {
        return;
    }

    bv->setSecFormat(enSecFormat);
}

void MainWindow::onAGFirstEndianTriggered()
{
    if (ui->actionFirstBigEndian->isChecked())
    {
        enFirstEndian = BIG_ENDIAN;
    }
    else
    {
        enFirstEndian = LITTLE_ENDIAN;
    }

    MdiSubWindow * sw = (MdiSubWindow *)ui->mdiArea->currentSubWindow();
    if (!sw)
    {
        return;
    }

    QString path = swMap.key(sw);
    if (path.isEmpty())
    {
        return;
    }

    BinView *bv = bvMap.value(path);
    if (!bv)
    {
        return;
    }

    bv->setFirstEndian(enFirstEndian);
}

void MainWindow::onAGSecEndianTriggered()
{
    if (ui->actionSecBigEndian->isChecked())
    {
        enSecEndian = BIG_ENDIAN;
    }
    else
    {
        enSecEndian = LITTLE_ENDIAN;
    }

    MdiSubWindow * sw = (MdiSubWindow *)ui->mdiArea->currentSubWindow();
    if (!sw)
    {
        return;
    }

    QString path = swMap.key(sw);
    if (path.isEmpty())
    {
        return;
    }

    BinView *bv = bvMap.value(path);
    if (!bv)
    {
        return;
    }

    bv->setSecEndian(enSecEndian);
}

void MainWindow::on_actionGitee_triggered()
{
    QProcess::startDetached("explorer https://gitee.com/lhzh527/binary-insight");
}
